#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <common/macro/build.h>
#include <common/io.h>
#include <transaction/abortlog.h>

API_LIBLOCAL abort_log_t *abort_log_open(const char *fn) {
	abort_log_t *abort_log;

	assert(fn != NULL);

	abort_log = malloc(sizeof(*abort_log));
	abort_log->file = io_open_rwc(fn);

	if (abort_log->file == NULL) {
		abort_log_close(abort_log);
		return NULL;
	}

	return abort_log;
}

API_LIBLOCAL int abort_log_check(abort_log_t *abort_log, transaction_id_t transaction_id) {
	transaction_id_t buffer[1024];
	ssize_t i, buflen;

	assert(abort_log != NULL);

	io_seek(abort_log->file, 0, SEEK_SET);
	
	do {
		buflen = io_read(buffer, sizeof(transaction_id_t), 1024, abort_log->file);
		for (i = 0; i < buflen; i++) {
			if (buffer[i] == transaction_id)
				return 1;
		}
	} while (buflen > 0);

	return 0;
}

API_LIBLOCAL int abort_log_clear(abort_log_t *abort_log) {
	assert(abort_log != NULL);
	assert(abort_log->file != NULL);

	return io_truncate(abort_log->file, 0);
}

API_LIBLOCAL int abort_log_add(abort_log_t *abort_log, transaction_id_t transaction_id) {
	io_seek(abort_log->file, 0, SEEK_END);
	return (io_write(&transaction_id, sizeof(transaction_id), 1, abort_log->file) == 1 ? 0 : -1);
}

API_LIBLOCAL int abort_log_flush(abort_log_t *abort_log) {
	return io_sync(abort_log->file);
}

API_LIBLOCAL void abort_log_close(abort_log_t *abort_log) {
	if (abort_log == NULL) return;

	if (abort_log->file != NULL)
		io_close(abort_log->file);
	free(abort_log);
}
